package com.api.demo.interceptor;

import java.io.IOException;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.exception.ExceptionUtils; // 添加依赖
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.ContentCachingRequestWrapper; // 请求包装器
import org.springframework.web.util.ContentCachingResponseWrapper;

import com.api.demo.entity.ApiLog;
import com.api.demo.entity.User;
import com.api.demo.service.ApiLogService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class ApiLogInterceptor extends HandlerInterceptorAdapter {
    private static final int MAX_BODY_SIZE = 10 * 1024;

    private final static Logger logger = LoggerFactory.getLogger(ApiLogInterceptor.class);

    @Resource
    private ApiLogService apiLogService;

    private ThreadLocal<Long> startTime = new ThreadLocal<>();



    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        startTime.set(System.currentTimeMillis());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) {
        try {
            long duration = System.currentTimeMillis() - startTime.get();
            startTime.remove();

            ApiLog logEntry = buildLogEntry(request, response, duration, ex);
            if (logEntry != null) {
                apiLogService.logAsync(logEntry);
            }
        } catch (Exception e) {
            logger.error("Failed to log request", e);
        } finally {
            startTime.remove();
        }
    }

    private ApiLog buildLogEntry(HttpServletRequest request, HttpServletResponse response,
            long duration, Exception ex) throws IOException {
        ApiLog log = new ApiLog();

        if (!(request instanceof ContentCachingRequestWrapper)) {
            logger.warn("Request not wrapped by filter");
            return null;
        }
        ContentCachingRequestWrapper wrappedRequest = (ContentCachingRequestWrapper) request;

        if (!(response instanceof ContentCachingResponseWrapper)) {
            logger.warn("Response not wrapped by filter");
            return null;
        }
        ContentCachingResponseWrapper wrappedResponse = (ContentCachingResponseWrapper) response;

        // ====== 新增：检查请求内容类型 ======
        String requestContentType = wrappedRequest.getContentType();
        boolean isTextRequest = requestContentType != null &&
                (requestContentType.startsWith("text/") ||
                        requestContentType.contains("json") ||
                        requestContentType.contains("xml") ||
                        requestContentType.contains("form-urlencoded"));

        // 请求体处理（带内容类型检查）
        if (isTextRequest) {
            byte[] requestBodyBytes = wrappedRequest.getContentAsByteArray();
            if (requestBodyBytes.length > 0) {
                if (requestBodyBytes.length > MAX_BODY_SIZE) {
                    log.setRequestBody("<请求体过大，已截断>");
                } else {
                    String requestBody = new String(requestBodyBytes, wrappedRequest.getCharacterEncoding());
                    log.setRequestBody(maskSensitiveData(requestBody));
                }
            }
        } else if (requestContentType != null) {
            // 非文本内容类型
            log.setRequestBody("<非文本内容：" + requestContentType + ">");
        } else {
            log.setRequestBody("<无内容类型>");
        }

        // ====== 新增：检查响应内容类型 ======
        String responseContentType = response.getContentType();
        boolean isTextResponse = responseContentType != null &&
                (responseContentType.startsWith("text/") ||
                        responseContentType.contains("json") ||
                        responseContentType.contains("xml"));

        // 响应体处理（带内容类型检查）
        if (isTextResponse) {
            byte[] responseBodyBytes = wrappedResponse.getContentAsByteArray();
            if (responseBodyBytes.length > 0) {
                if (responseBodyBytes.length > MAX_BODY_SIZE) {
                    log.setResponseBody("<响应体过大，已截断>");
                } else {
                    String responseBody = new String(responseBodyBytes, wrappedResponse.getCharacterEncoding());
                    log.setResponseBody(maskSensitiveData(responseBody));
                }
            }
        } else if (responseContentType != null) {
            // 非文本内容类型
            log.setResponseBody("<非文本内容：" + responseContentType + ">");
        } else {
            log.setResponseBody("<无内容类型>");
        }

        // 基础信息
        log.setRequestId(UUID.randomUUID().toString());
        log.setMethod(wrappedRequest.getMethod());
        log.setPath(wrappedRequest.getRequestURI());
        log.setQueryString(wrappedRequest.getQueryString());
        log.setStatusCode(response.getStatus());
        log.setClientIp(getClientIp(wrappedRequest));
        log.setDuration(duration);
        log.setRequestTime(new Date());
        log.setResponseSize((long) response.getBufferSize()); // int转long

        // 用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication != null && authentication.getPrincipal() instanceof User) {
            User user = (User) authentication.getPrincipal();
            log.setUserId(user.getId());
            log.setUsername(user.getUsername());
        } else {
            log.setUserId(-1L); // 匿名用户标识
            log.setUsername("anonymous");
        }

        // 请求头
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = wrappedRequest.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName, wrappedRequest.getHeader(headerName));
        }
        log.setRequestHeaders(headers);

        // 记录响应大小（修正）
        byte[] responseBodyBytes = wrappedResponse.getContentAsByteArray();
        log.setResponseSize((long) responseBodyBytes.length);

        // 异常信息（使用ExceptionUtils）
        if (ex != null) {
            log.setErrorMsg(ExceptionUtils.getStackTrace(ex)); // 需要添加依赖
            // 或使用原生方法:
            // StringWriter sw = new StringWriter();
            // ex.printStackTrace(new PrintWriter(sw));
            // log.setErrorMsg(sw.toString());
        }

        return log;
    }

    private String maskSensitiveData(String body) {
        // 实现脱敏逻辑
        if (body == null)
            return null;
        // 匹配: password=value, token:value, "key":"value" 等
        return body.replaceAll("(?i)(password|token|key)(\\s*[:=]\\s*)([^&\s]+)", "$1$2******");
    }

    private String getClientIp(HttpServletRequest request) {
        // 获取客户端IP
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
